package com.xinyuan.trade.Widght;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;

import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import android.util.Log;

/**
 * Utility class for setting WebKit proxy used by Android WebView
 *
 */
public class ProxySettings {
	private static ContentResolver _contentResolver;
	private static String _proxyString;
	private static String _proxyAddress;
	private static Integer _proxyPort;
	private static Boolean _proxyStatus = null;

	private static String getSystemProxyAddress(Context ctx) {
		if (isSystemProxyValid(ctx)) {
			_proxyAddress = _proxyString.split(":")[0];
			return _proxyAddress;
		} else
			return null;
	}

	private static Integer getSystemProxyPort(Context ctx) {
		if (isSystemProxyValid(ctx)) {
			_proxyPort = Integer.parseInt(_proxyString.split(":")[1]);
			return _proxyPort;
		} else
			return null;
	}

	private static boolean isSystemProxyValid(Context ctx) {
		_contentResolver = ctx.getContentResolver();
		_proxyString = Settings.Secure.getString(_contentResolver,
				Settings.Secure.HTTP_PROXY);
		if (_proxyString != null && _proxyString != ""
				&& _proxyString.contains(":")) {
			return true;
		} else {
			return false;
		}
	}

	private static boolean isSystemProxyReachable(Context ctx) {
		int exitValue;
		Runtime runtime = Runtime.getRuntime();
		Process proc;

		try {
			proc = runtime.exec("ping -c 1   " + getSystemProxyAddress(ctx));
			proc.waitFor();
			exitValue = proc.exitValue();

			Log.d("ProxySettings", "Ping exit value: " + exitValue);

			if (exitValue == 0)
				return true;
			else
				return false;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		return false;
	}

	private static boolean isInternetReachable(Context ctx) {
		DefaultHttpClient httpclient = new DefaultHttpClient();
		HttpHost proxy = new HttpHost(getSystemProxyAddress(ctx),
				getSystemProxyPort(ctx));
		httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
				proxy);

		HttpGet request;
		HttpResponse response;

		try {
			request = new HttpGet("http://www.google.com");
			response = httpclient.execute(request);

			Log.d("ProxySettings", "Is internet reachable : "
					+ response.getStatusLine().toString());
			if (response != null
					&& response.getStatusLine().getStatusCode() == 200) {
				return true;
			} else
				return false;
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return false;
	}

	// private static boolean testSystemProxy(Context ctx) {
	// String message = "";
	//
	// if (!isSystemProxyValid(ctx)) {
	// _proxyStatus = false;
	// message = ctx.getResources().getString(
	// R.string.ProxySettings_ErrorProxySettingsNotValid);
	// } else if (!isSystemProxyReachable(ctx)) {
	// _proxyStatus = false;
	// message = ctx.getResources().getString(
	// R.string.ProxySettings_ErrorProxyServerNotReachable);
	// } else if (!isInternetReachable(ctx)) {
	// _proxyStatus = false;
	// message = ctx.getResources().getString(
	// R.string.ProxySettings_ErrorProxyInternetNotReachable);
	// } else {
	// _proxyStatus = true;
	// }
	//
	// if (!_proxyStatus)
	// Toast.makeText(ctx, message, Toast.LENGTH_LONG).show();
	//
	// return _proxyStatus;
	// }

	public static void setSystemProxy(Context ctx) {
		// Toast.makeText(ctx,
		// ctx.getResources().getString(R.string.ProxySettings_EnablingProxySettings),
		// Toast.LENGTH_SHORT).show();

		// if (_proxyStatus == null || _proxyStatus == false)
		// testSystemProxy(ctx);

		if (_proxyStatus) {
			setProxy(ctx, getSystemProxyAddress(ctx), getSystemProxyPort(ctx));
			// Toast.makeText(ctx,
			// ctx.getResources().getString(R.string.ProxySettings_ProxySettingsEnabled),
			// Toast.LENGTH_LONG).show();
		} else
			resetSystemProxy(ctx);
	}

	public static void resetSystemProxy(Context ctx) {
		if (_proxyStatus != null && _proxyStatus == true) {
			try {
				resetProxy(ctx);
			} catch (Exception e) {
				Log.e("ProxySettings",
						"Exception resetting WebKit proxy settings: "
								+ e.toString());
			}
		}
	}

	private static boolean setProxy(Context ctx, String host, int port) {
		boolean ret = false;
		try {
			Object requestQueueObject = getRequestQueue(ctx);
			if (requestQueueObject != null) {
				// Create Proxy config object and set it into request Q
				HttpHost httpHost = new HttpHost(host, port, "http");
				setDeclaredField(requestQueueObject, "mProxyHost", httpHost);
				// Log.d("Webkit Setted Proxy to: " + host + ":" + port);
				ret = true;
			}
		} catch (Exception e) {
			Log.e("ProxySettings", "Exception setting WebKit proxy settings: "
					+ e.toString());
		}
		return ret;
	}

	private static void resetProxy(Context ctx) throws Exception {
		Object requestQueueObject = getRequestQueue(ctx);
		if (requestQueueObject != null) {
			setDeclaredField(requestQueueObject, "mProxyHost", null);
		}
	}

	@SuppressWarnings("rawtypes")
	private static Object GetNetworkInstance(Context ctx)
			throws ClassNotFoundException {
		Class networkClass = Class.forName("android.webkit.Network");
		return networkClass;
	}

	private static Object getRequestQueue(Context ctx) throws Exception {
		Object ret = null;
		Object networkClass = GetNetworkInstance(ctx);
		if (networkClass != null) {
			Object networkObj = invokeMethod(networkClass, "getInstance",
					new Object[] { ctx }, Context.class);
			if (networkObj != null) {
				ret = getDeclaredField(networkObj, "mRequestQueue");
			}
		}
		return ret;
	}

	private static Object getDeclaredField(Object obj, String name)
			throws SecurityException, NoSuchFieldException,
			IllegalArgumentException, IllegalAccessException {
		Field f = obj.getClass().getDeclaredField(name);
		f.setAccessible(true);
		Object out = f.get(obj);
		return out;
	}

	private static void setDeclaredField(Object obj, String name, Object value)
			throws SecurityException, NoSuchFieldException,
			IllegalArgumentException, IllegalAccessException {
		Field f = obj.getClass().getDeclaredField(name);
		f.setAccessible(true);
		f.set(obj, value);
	}

	@SuppressWarnings("rawtypes")
	private static Object invokeMethod(Object object, String methodName,
			Object[] params, Class... types) throws Exception {
		Object out = null;
		Class c = object instanceof Class ? (Class) object : object.getClass();

		if (types != null) {
			Method method = c.getMethod(methodName, types);
			out = method.invoke(object, params);
		} else {
			Method method = c.getMethod(methodName);
			out = method.invoke(object);
		}
		return out;
	}
}
